package me.seu.demo.service.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import me.seu.demo.service.netty.constants.ProtocolConstants;
import me.seu.demo.service.netty.message.GpsMessage;
import me.seu.demo.service.netty.utils.ByteUtils;
import me.seu.demo.service.netty.utils.CommUtils;
import me.seu.demo.service.netty.utils.CrcItuUtils;

import java.util.List;

/**
 * 自定义帧解码器
 *
 * @author liangfeihu
 * @number 53669
 * @since 2021/3/29 上午9:47
 */
@Slf4j
public class TransferDecoder extends ByteToMessageDecoder {

    private static final int MINI_DATA_LENGTH = 6;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // tcp分包采用的格式是
        // 起始位2 包长度1或2 协议号1 信息内容N 信息序列号2 错误校验2 停止位2
        if (in.readableBytes() < MINI_DATA_LENGTH) {
            ctx.pipeline().close();
            return;
        }

        // 包长度
        byte len = in.readByte();
        int packageLength = 0xFF & len;
        log.info("包长度：hex=0x{} len={}", ByteUtils.byteToHexString(len), packageLength);

        // 协议号
        byte protocolNumber = in.readByte();
        log.info("协议号：hex=0x{}", ByteUtils.byteToHexString(protocolNumber));

        // 内容信息
        int contentLength = packageLength - 1 - 2 - 2;
        byte[] dataContent = new byte[contentLength];
        in.readBytes(dataContent);
        log.info("信息内容：hex=0x{}", ByteUtils.bytesToHexString(dataContent));

        // seqNum
        byte[] seqNum = new byte[2];
        in.readBytes(seqNum);
        log.info("信息序列号：hex=0x{}", ByteUtils.bytesToHexString(seqNum));

        // crc
        byte[] crcData = new byte[2];
        in.readBytes(crcData);
        log.info("错误校验码：hex=0x{}", ByteUtils.bytesToHexString(crcData));

        boolean flag = CrcItuUtils.checkCrc(len, protocolNumber, dataContent, seqNum, crcData);
        log.info("[TransferDecoder] channel Read one {} message.", flag);
        if (!flag) {
            // CRC校验错误，丢弃该消息
            log.error("[TransferDecoder] channel Read message CRC error.");
            ctx.pipeline().close();
            return;
        }

        GpsMessage eventMsg = new GpsMessage(protocolNumber, dataContent, seqNum);
        String deviceId = "";
        if (ProtocolConstants.PROTOCOL_LOGIN == protocolNumber) {
            deviceId = CommUtils.getDeviceIdFromByte(dataContent);
            CommUtils.setDeviceIdAttr(ctx, deviceId);
        } else {
            deviceId = CommUtils.getDeviceIdFromAttr(ctx);
        }

        eventMsg.setDeviceId(deviceId);
        eventMsg.setCtx(ctx);
        out.add(eventMsg);
    }

}
